package com.fileupload.server;

import com.fileupload.config.ServerConfig;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * SFTP连接实现类
 */
public class SftpConnection implements Connection {
    private static final Logger logger = LoggerFactory.getLogger(SftpConnection.class);
    
    private ServerConfig serverConfig;
    private JSch jsch;
    private Session session;
    private ChannelSftp channel;
    
    public SftpConnection(ServerConfig serverConfig) {
        this.serverConfig = serverConfig;
        this.jsch = new JSch();
    }
    
    @Override
    public boolean connect() throws IOException {
        try {
            String[] addrParts = serverConfig.getAddr().split(":");
            String host = addrParts[0];
            int port = addrParts.length > 1 ? Integer.parseInt(addrParts[1]) : 22;
            
            // 创建会话
            session = jsch.getSession(serverConfig.getUsername(), host, port);
            session.setPassword(serverConfig.getPasswd());
            
            // 设置会话属性
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            
            // 连接会话
            session.connect(5000); // 超时5秒
            
            // 打开SFTP通道
            channel = (ChannelSftp) session.openChannel("sftp");
            channel.connect();
            
            logger.info("SFTP服务器连接成功: {}", serverConfig.getName());
            return true;
        } catch (JSchException e) {
            logger.error("SFTP连接异常: {}", e.getMessage());
            disconnect(); // 确保资源释放
            throw new IOException("SFTP连接失败", e);
        }
    }
    
    @Override
    public void disconnect() throws IOException {
        try {
            if (channel != null && channel.isConnected()) {
                channel.disconnect();
            }
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
            logger.info("SFTP服务器断开连接: {}", serverConfig.getName());
        } catch (Exception e) {
            logger.error("SFTP断开连接异常: {}", e.getMessage());
            throw new IOException("SFTP断开连接失败", e);
        }
    }
    
    @Override
    public boolean isConnected() {
        return session != null && session.isConnected() && channel != null && channel.isConnected();
    }
    
    @Override
    public boolean uploadFile(File file, String remotePath, String remoteFileName) throws IOException {
        if (!isConnected()) {
            logger.warn("SFTP未连接，无法上传文件");
            return false;
        }
        
        try {
            // 确保远程目录存在
            if (!remotePath.endsWith("/")) {
                remotePath = remotePath + "/";
            }
            String fullRemotePath = remotePath + remoteFileName;
            
            String remoteDir = remotePath;
            if (!directoryExists(remoteDir)) {
                createDirectory(remoteDir);
            }
            
            channel.put(file.getAbsolutePath(), fullRemotePath);
            logger.info("文件上传成功: {} -> {}", file.getAbsolutePath(), fullRemotePath);
            return true;
        } catch (SftpException e) {
            logger.error("文件上传异常: {}", e.getMessage());
            throw new IOException("SFTP文件上传失败", e);
        }
    }
    
    @Override
    public boolean createDirectory(String directory) throws IOException {
        if (!isConnected()) {
            return false;
        }
        
        try {
            // 递归创建目录
            String[] dirs = directory.split("/");
            StringBuilder currentDir = new StringBuilder();
            
            for (String dir : dirs) {
                if (dir.isEmpty()) continue;
                
                currentDir.append("/").append(dir);
                String path = currentDir.toString();
                
                try {
                    channel.cd(path);
                } catch (SftpException e) {
                    try {
                        channel.mkdir(path);
                        channel.cd(path);
                    } catch (SftpException ex) {
                        logger.error("创建目录失败: {}", path);
                        return false;
                    }
                }
            }
            
            logger.info("目录创建成功: {}", directory);
            return true;
        } catch (Exception e) {
            logger.error("创建目录异常: {}", e.getMessage());
            throw new IOException("SFTP创建目录失败", e);
        }
    }
    
    @Override
    public boolean directoryExists(String directory) throws IOException {
        if (!isConnected()) {
            return false;
        }
        
        try {
            String currentDir = channel.pwd();
            channel.cd(directory);
            channel.cd(currentDir); // 恢复当前目录
            return true;
        } catch (SftpException e) {
            return false;
        }
    }
    
    @Override
    public boolean writeTextFile(String remotePath, String content) throws IOException {
        if (!isConnected()) {
            return false;
        }
        
        try {
            // 确保远程目录存在
            String remoteDir = remotePath.substring(0, remotePath.lastIndexOf('/'));
            if (!directoryExists(remoteDir)) {
                createDirectory(remoteDir);
            }
            
            channel.put(new java.io.ByteArrayInputStream(content.getBytes("UTF-8")), remotePath);
            logger.info("文本文件写入成功: {}", remotePath);
            return true;
        } catch (SftpException e) {
            logger.error("文本文件写入异常: {}", e.getMessage());
            throw new IOException("SFTP写入文本文件失败", e);
        }
    }
    
    @Override
    public boolean renameFile(String oldFilePath, String newFilePath) throws IOException {
        if (!isConnected()) {
            logger.warn("SFTP未连接，无法重命名文件");
            return false;
        }
        
        try {
            channel.rename(oldFilePath, newFilePath);
            logger.info("文件重命名成功: {} -> {}", oldFilePath, newFilePath);
            return true;
        } catch (SftpException e) {
            logger.error("文件重命名异常: {}", e.getMessage());
            throw new IOException("SFTP文件重命名失败", e);
        }
    }
}